Profile picture

[k8s] Deep Dive - 로드밸런서

JaehyoJJAng2023년 04월 04일

Loadbalancer

로드밸런서는 서버에 가해지는 부하를 분산해주는 기술 및 장치로 클라이언트와 서버 사이에 위치하여 한 대의 서버로 부하가 집중되지 않도록 트래픽을 관리해 각각의 서버가 최적의 성능을 내도록 한다.
image


쿠버네티스에서도 로드밸런서를 사용 가능하며 이전 포스트의 NodePort 방식과 같은 경우 클라이언트의 요청을 모두 워커 노드의 노드포트를 통해 노드포트 서비스로 이동하고 이를 다시 각 파드로 보내는 방식이기 때문에 비효율적이라고 볼수 있다.
image


하지만 로드밸런서를 사용한다면 다음과 같은 구조로 간단하게 외부에 노출하고 부하를 분산할 수 있다.
image


하지만 로드밸런서를 사용하기 위해서는 쿠버네티스를 클라우드 환경에 구축하고 해당 클라우드에서 제공하는 로드밸런서(ELB ..)를 사용하여 클러스터 외부에 구현해주어야 한다.


MetalLB

현재 로컬에 온프레미스 환경으로 클러스터를 구축했기 때문에 외부에서 제공받을 로드밸런스가 따로 존재하지 않는다.

하지만 온프레미스에서도 로드밸런서를 사용할 수 있도록 고안된 프로젝트인 metalLB를 사용하면 로컬의 온프레미스 환경에서도 로드밸런서 구축이 가능하다.

MetalLB는 특별한 네트워크 설정이나 구성이 있는 것이 아니라 기존의 L2/L3 네트워크로 로드밸런서를 구현하기 때문에 새로 배워야 할 부담이 적고 연동이 매우 쉽다는 장점이 있다.


실습

실습으로 MetalLB의 L2 네트워크로 로드밸런서를 구현하고 아래와 같이 두 개의 MetalbLB 로드밸런서 서비스를 구현한다.
사용자가 로드밸런서 서비스에 접근하면 서비스에서 파드로 포워딩 해주는 구조이다. image

아래 작업을 따라해보자.


1. 디플로이먼트를 이용해 2종류(lb-hname-pods,lb-ip-pods)의 파드를 생성하자. 그리고 scale 명령으로 파드를 2개로 늘려 노드당 1개씩 파드가 배포되도록 하자

$ kubectl create deployment lb-hname-pods --image=sysnet4admin/echo-hname
$ kubectl scale deployment/lb-hname-pods --replicas=2

$ kubectl create deployment lb-ip-pods --image=sysnet4admin/echo-ip
$ kubectl scale deployment/lb-ip-pods --replicas=2

2. 2종류의 파드가 2개씩 총 4개가 배포되었는지 확인

$ kubectl get pods -o wide
NAME                             READY   STATUS    RESTARTS   AGE   IP               NODE     NOMINATED NODE   READINESS GATES
lb-hname-pods-79b95c7c7b-rd799   1/1     Running   0          90s   172.16.103.145   w2-k8s   <none>           <none>
lb-hname-pods-79b95c7c7b-sdclw   1/1     Running   0          81s   172.16.221.186   w1-k8s   <none>           <none>
lb-ip-pods-6c6bb59b4-8jlxz       1/1     Running   0          38s   172.16.103.146   w2-k8s   <none>           <none>
lb-ip-pods-6c6bb59b4-xm9d2       1/1     Running   0          33s   172.16.221.187   w1-k8s   <none>           <none>

3. 인그레스와 마찬가지로 사전에 정의된 오브젝트 스펙으로 MetalLB를 구성한다.

$ kubectl apply -f ~/_Book_k8sInfra/ch3/3.3.4/metallb.yaml
namespace/metallb-system created
podsecuritypolicy.policy/speaker created
serviceaccount/controller created
serviceaccount/speaker created
clusterrole.rbac.authorization.k8s.io/metallb-system:controller created
clusterrole.rbac.authorization.k8s.io/metallb-system:speaker created
role.rbac.authorization.k8s.io/config-watcher created
clusterrolebinding.rbac.authorization.k8s.io/metallb-system:controller created
clusterrolebinding.rbac.authorization.k8s.io/metallb-system:speaker created
rolebinding.rbac.authorization.k8s.io/config-watcher created
daemonset.apps/speaker created
deployment.apps/controller created

4. 배포된 metalLB의 파드가 5개(Controller 1개, speaker 4개)인지 확인하고 IP와 상태도 확인

$ kubectl get pods -n metallb-system -o wide
NAME                          READY   STATUS    RESTARTS   AGE   IP               NODE     NOMINATED NODE   READINESS GATES
controller-5d48db7f99-9g2t6   1/1     Running   0          52s   172.16.221.188   w1-k8s   <none>           <none>
speaker-2ptq8                 1/1     Running   0          52s   192.168.1.101    w1-k8s   <none>           <none>
speaker-l6p5h                 1/1     Running   0          52s   192.168.1.10     m-k8s    <none>           <none>
speaker-mplg6                 1/1     Running   0          52s   192.168.1.102    w2-k8s   <none>           <none>

5. 인그레스와 마찬가지로 MetalLB도 설정을 적용해야 한다. 이 때 오브젝트는 ConfigMap을 사용함. ConfigMap은 설정이 정의된 포맷이라고 생각하면 된다.

$ kubectl apply -f ~/_Book_k8sInfra/ch3/3.3.4/metallb-l2config.yaml
configmap/config created

파일 구성은 아래와 같다

apiVersion: v1
kind: ConfigMap
metadata:
  namespace: metallb-system
  name: config
data:
  config: |
    address-pools:
    - name: nginx-ip-range
      protocol: layer2
      addresses:
      - 192.168.1.11-192.168.1.13

6. ConfigMap이 생성되었는지 확인

$ kubectl get configmap -n metallb-system
NAME     DATA   AGE
config   1      71s

7. -o yaml 옵션을 주고 다시 실행해 MetalLB의 설정이 올바르게 적용 되었는지 확인

$ kubectl get configmap -n metallb-system -o yaml

8. 모든 설정이 완료됐으니 이제 각 디플로이먼트(lb-hname-pods,lb-ip-pods)를 로드밸런서 서비스로 노출

$ kubectl expose deployment/lb-hname-pods --type=LoadBalancer --name=lb-hname-svc --port=80
service/lb-hname-svc exposed

$ kubectl expose deployment/lb-ip-pods --type=LoadBalancer --name=lb-ip-svc --port=80
service/lb-ip-svc exposed

9. 생성된 로드밸런서 서비스별로 CLUSTER-IP와 EXTERNAL-IP가 잘 적용되었는지 확인하자. 특히 EXTERNAL-IP에 ConfigMap을 통해 부여한 IP를 확인

$ kubectl get svc -o wide
NAME           TYPE           CLUSTER-IP     EXTERNAL-IP    PORT(S)        AGE    SELECTOR
kubernetes     ClusterIP      10.96.0.1      <none>         443/TCP        4d2h   <none>
lb-hname-svc   LoadBalancer   10.97.197.98   192.168.1.11   80:32457/TCP   89s    app=lb-hname-pods
lb-ip-svc      LoadBalancer   10.103.52.73   192.168.1.12   80:30480/TCP   63s    app=lb-ip-pods

10. 로컬 PC에서 웹 브라우저 접속 OR 터미널 창에서 curl로 테스트

# 192.168.1.12를 접속해 파드에 요청 방법과 IP가 표시되는지 확인
$ curl -X GET 192.168.1.12
request_method : GET | ip_dest: 172.16.103.146

다음 실습을 위해 배포한 Deployment와 서비스는 삭제하자.

kubectl delete deployment/lb-hname-pods
kubectl delete deployment/lb-ip-pods
kubectl delete svc/lb-hname-svc
kubectl delete svc/lb-ip-svc

Loading script...